package net.tavion.angelboot.gateway.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import net.tavion.angelboot.bsm.client.BsmClient;
import net.tavion.angelboot.bsm.dto.CustomerInfoDTO;
import net.tavion.angelboot.bsm.dto.CustomerReqDTO;
import net.tavion.angelboot.bsm.dto.SystemKeyInfoDTO;
import net.tavion.angelboot.common.enums.AngelChannel;
import net.tavion.angelboot.common.enums.RequestHeaderElement;
import net.tavion.angelboot.common.enums.SystemCode;
import net.tavion.angelboot.common.extend.SpringExtensionLoader;
import net.tavion.angelboot.common.utils.FrameworkUtils;
import net.tavion.angelboot.common.utils.ObjectMapperUtils;
import net.tavion.angelboot.common.vo.GenericResponse;
import net.tavion.angelboot.gateway.jwt.JwtProperties;
import net.tavion.angelboot.gateway.jwt.JwtUtil;
import net.tavion.angelboot.gateway.vo.UserLoginRspVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.server.WebFilterExchange;
import org.springframework.security.web.server.authentication.WebFilterChainServerAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;


@Component
@Slf4j
public class AuthenticationSuccessHandler extends WebFilterChainServerAuthenticationSuccessHandler {

    @Resource
    ObjectMapper mapper;
    @Override
    public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication){

        List<String> channelKeyList = webFilterExchange.getExchange().getRequest().getHeaders().get(RequestHeaderElement.channelKey.getCode());

        GenericResponse<SystemKeyInfoDTO> systemKeyInfoDTOGenericResponse =null;
        boolean headerChannekKeyVaild=CollectionUtils.isEmpty(channelKeyList) || StringUtils.isBlank(channelKeyList.get(0));
        BsmClient bsmClient= SpringExtensionLoader.getSpringBean(BsmClient.class);
        if(!headerChannekKeyVaild){
            String channelKey =channelKeyList.get(0);
            systemKeyInfoDTOGenericResponse =bsmClient.validKey(channelKey);

            headerChannekKeyVaild= FrameworkUtils.notCallSuccess(systemKeyInfoDTOGenericResponse) ||systemKeyInfoDTOGenericResponse.getData()==null;

            if(!headerChannekKeyVaild){
                String channelCode= systemKeyInfoDTOGenericResponse.getData().getChannelCode();
                headerChannekKeyVaild=!AngelChannel.validate(channelCode);
            }
        }

        if(headerChannekKeyVaild){
            GenericResponse failResponse=new GenericResponse();
            failResponse.setCode(SystemCode.HEADER_ERROR.getCode());
            failResponse.setMessage(SystemCode.HEADER_ERROR.getMessage());
            byte[]  dataBytes= ObjectMapperUtils.writeAsString(failResponse,mapper).getBytes();
            DataBuffer bodyDataBuffer = webFilterExchange.getExchange().getResponse().bufferFactory().wrap(dataBytes);
            return webFilterExchange.getExchange().getResponse().writeWith(Mono.just(bodyDataBuffer));
        }

        User user = (User) authentication.getPrincipal();

        String role = "";
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        for (GrantedAuthority authority : authorities){
            role = authority.getAuthority();
        }

        CustomerReqDTO customerReqDTO=new CustomerReqDTO();
        customerReqDTO.setUsername(user.getUsername());
        GenericResponse<CustomerInfoDTO> customerInfoDTOGenericResponse =bsmClient.info(customerReqDTO);
        if (FrameworkUtils.notCallSuccess(customerInfoDTOGenericResponse)) {
            throw  new BadCredentialsException("账户信息异常");
        }

        // get spring bean
        StringRedisTemplate stringRedisTemplate = SpringExtensionLoader.getSpringBean(StringRedisTemplate.class);
        JwtUtil jwtUtil = SpringExtensionLoader.getSpringBean(JwtUtil.class);
        JwtProperties jwtProperties = SpringExtensionLoader.getSpringBean(JwtProperties.class);

        Map<String, Object> map = new HashMap<>(2);
        map.put(JwtUtil.ROL, role);
        map.put(JwtUtil.REQUESTCHANNEL, systemKeyInfoDTOGenericResponse.getData());

        String token = jwtUtil.createJWT(user.getUsername(), map);

        Integer expiredTime = jwtProperties.getExpiredTime();
        if(null == expiredTime || expiredTime <=0 ){
            expiredTime= 30;
        }

        String channelCode= systemKeyInfoDTOGenericResponse.getData().getChannelCode();
        String tokenKey="TOKEN:"+channelCode+":"+user.getUsername();


        stringRedisTemplate.opsForValue().set(tokenKey,token, expiredTime, TimeUnit.MINUTES);

        ServerWebExchange exchange = webFilterExchange.getExchange();
        ServerHttpResponse response = exchange.getResponse();
        //设置headers
        HttpHeaders httpHeaders = response.getHeaders();
        httpHeaders.add("Content-Type", "application/json; charset=UTF-8");
        httpHeaders.add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");



        httpHeaders.add(RequestHeaderElement.authorization.getCode(), JwtUtil.TOKEN_PREFIX + token);
        response.setStatusCode(HttpStatus.OK);

        UserLoginRspVO userLoginRspVO = new UserLoginRspVO();

        userLoginRspVO.setUserid(customerInfoDTOGenericResponse.getData().getUserid());

        userLoginRspVO.setNickname(customerInfoDTOGenericResponse.getData().getUsername());
        userLoginRspVO.setUsername(customerInfoDTOGenericResponse.getData().getUsername());
        userLoginRspVO.setDays(15);
        GenericResponse<UserLoginRspVO> genericResponse = new GenericResponse<>(userLoginRspVO);

        genericResponse.setCode(SystemCode.SUCCESS.getCode());
        genericResponse.setMessage(SystemCode.SUCCESS.getMessage());
        byte[] dataBytes= ObjectMapperUtils.writeValueAsBytes(genericResponse,mapper);
        DataBuffer bodyDataBuffer = response.bufferFactory().wrap(dataBytes);
        return response.writeWith(Mono.just(bodyDataBuffer));
    }



    private UserLoginRspVO  buildUser(User user){
        UserLoginRspVO userDetails=new UserLoginRspVO();
        userDetails.setUsername(user.getUsername());
        userDetails.setNickname(user.getPassword().substring(user.getPassword().lastIndexOf("}")+1,user.getPassword().length()));
        return userDetails;
    }





}
